/**
 * @file extio_mgr.c
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2020-09-15
 * 
 * @copyright Copyright (c) 2020
 * 
 */
#include <stdio.h>
#include <stdlib.h>  // needed for sysconf(int name);
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <time.h>
#include <getopt.h>
#include <signal.h>
#include <sys/mman.h>  // Needed for mlockall()
#include <malloc.h>
#include <sys/time.h>      // needed for getrusage
#include <sys/resource.h>  // needed for getrusage
#include <sys/shm.h>
#include <limits.h>
#include <string>
#include "zuc/nml_intf/zucpos.h"
#include "3rd/libmodbus/modbus.h"
#include "extio_mgr.h"
#include "config.h"
#include "modbus_io_mgr.h"
#include "log/zuclog.h"

static int lastExtIOErrCode = 0;
static int lastExtIOStatus = 0;
static int reConnectCnt = 0;
static int extioRTU_offlineCnt = 0;
pthread_mutex_t rtu_ctx_lock;
/*
 * make the stack a little bigger
*/

#define MODBUS_CONNECTION_FAIL_CNT_MAX (5)

#define EXTIO_MODBUS_DEBUG (0)

extern ModbusIOShm_t* ModbusIOShmStruct;

static modbus_t* rtu_ctx = NULL;

static uint8_t isRobotiqType(const char* modName)
{
    char sufix[MAX_EXTIO_NAME_LEN] = "_tq";  // downcase
    int sufixLen = strlen(sufix);
    char tmpName[MAX_EXTIO_NAME_LEN];  ///< name of IO module
    strncpy(tmpName, modName, MAX_EXTIO_NAME_LEN);
    tmpName[MAX_EXTIO_NAME_LEN - 1] = '\0';

    for (int index = strlen(tmpName) - 1; index >= sufixLen; index--)
    {
        if ((tmpName[index] == ' ') || (tmpName[index] == '\t') || (tmpName[index] == '\r')) /* ignore blank or tab or CR */
            continue;

        if ((tmpName[index] == sufix[sufixLen - 1] || tmpName[index] + 32 == sufix[sufixLen - 1]) &&
            (tmpName[index - 1] == sufix[sufixLen - 2] || tmpName[index - 1] + 32 == sufix[sufixLen - 2]) &&
            (tmpName[index - 2] == sufix[sufixLen - 3] || tmpName[index - 1] + 32 == sufix[sufixLen - 3]))
        {
            zucInnerDbg("######### modName=%s,  isRoboticType = TRUE \n", modName);
            return 1;  // is Robotiq  Modbus Slave
        }
        else
        {
            return 0;
        }
    }
    return 0;
}

typedef struct local_config_mgr_s
{
    ExtIOSetup extIOCfg;
    int shm_index;
    modbus_t* modbus_ctx;
    int connection_fail_cnt;
    int connection_read_in_reg_fail_cnt;
    int connection_write_reg_fail_cnt;

    int connection_write_bits_fail_cnt;
    int connection_read_regs_fail_cnt;
    int connection_read_bits_fail_cnt;
    /*
	 * connection status
	 * 0: init
	 * 1: normal
	 * 2: offline
	 */
    int connection_sts;
    uint8_t supportRobotiq;
} local_config_mgr_t;

static local_config_mgr_t local_config_mgr_rtu[32];
static local_config_mgr_t local_config_mgr_tcp[32];

static int modbus_init_cmplt = 0;
static int modbus_Init_req = 0;

/**
 * @brief 
 * * debug perpose:
 * show configuration from motion
 */
static void extio_debug_show_config()
{
    int i;
    zucInnerDbg("EXTIO:>> share memory cfg:\n");
    zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.mode = %d\n", ModbusIOShmStruct->extIOShmStruct.mode);
    for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModCount; i++)
    {
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.extType = %d\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.extType);
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.modName = %s\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.modName);
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.ExtIOModInfo = %s\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.ExtIOModInfo);
        if (ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.extType == 0)
        {
            zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.commInfo.rtuComm.baudrate = %d\n",
                        i,
                        ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.commInfo.rtuComm.baudrate);
            zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.commInfo.rtuComm.databits = %d\n",
                        i,
                        ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.commInfo.rtuComm.databits);
            zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.commInfo.rtuComm.slaveId = %d\n",
                        i,
                        ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.commInfo.rtuComm.slaveId);
            zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.commInfo.rtuComm.stopbits = %d\n",
                        i,
                        ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.commInfo.rtuComm.stopbits);
            zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.commInfo.rtuComm.parity = %d\n",
                        i,
                        ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.commInfo.rtuComm.parity);
        }
        else if (ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.extType == 1)
        {
            zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.commInfo.tcpComm.ipaddr = %s\n",
                        i,
                        ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.commInfo.tcpComm.ipaddr);
            zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.commInfo.tcpComm.port = %d\n",
                        i,
                        ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.commInfo.tcpComm.port);
        }
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.diSetup.startRegAddr = %d\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.diSetup.startRegAddr);
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.diSetup.pinNum = %d\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.diSetup.pinNum);
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.doSetup.startRegAddr = %d\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.doSetup.startRegAddr);
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.doSetup.pinNum = %d\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.doSetup.pinNum);
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.aiSetup.startRegAddr = %d\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.aiSetup.startRegAddr);
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.aiSetup.pinNum = %d\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.aiSetup.pinNum);
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.aoSetup.startRegAddr = %d\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.aoSetup.startRegAddr);
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.aoSetup.pinNum = %d\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.aoSetup.pinNum);
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOMap.diStartIdx = %d\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOMap.diStartIdx);
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOMap.doStartIdx = %d\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOMap.doStartIdx);
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOMap.aiStartIdx = %d\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOMap.aiStartIdx);
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOMap.aoStartIdx = %d\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOMap.aoStartIdx);
    }
}
/**
 * @brief 
 *  * debug perpose:
 * show data of share memory
 */
#if (EXTIO_MODBUS_DEBUG == 1)
static void extio_debug_show_data()
{
    int i, j;
    zucInnerDbg("EXTIO:>> share memory data:\n");

    for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModCount; i++)
    {
        zucInnerDbg("EXTIO:>> Show IO status:\n");
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.extType = %d\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.extType);
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.modName = %s\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.modName);
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.ExtIOModInfo = %s\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.ExtIOModInfo);
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOMap.diStartIdx = %d\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOMap.diStartIdx);
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.diSetup.pinNum = %d\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.diSetup.pinNum);
        for (j = ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOMap.diStartIdx;
             j < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOMap.diStartIdx +
                     ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.diSetup.pinNum;
             j++)
        {
            zucInnerDbg("[%d]-", ModbusIOShmStruct->extIOShmStruct.extIOStat.extDI[j]);
        }
        zucInnerDbg("\n");
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOMap.doStartIdx = %d\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOMap.doStartIdx);
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.doSetup.pinNum = %d\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.doSetup.pinNum);
        for (j = ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOMap.doStartIdx;
             j < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOMap.doStartIdx +
                     ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.doSetup.pinNum;
             j++)
        {
            zucInnerDbg("[%d]-", ModbusIOShmStruct->extIOShmStruct.extIOCtrl.extDO[j]);
        }
        zucInnerDbg("\n");
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOMap.aiStartIdx = %d\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOMap.aiStartIdx);
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.aiSetup.pinNum = %d\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.aiSetup.pinNum);
        for (j = ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOMap.aiStartIdx;
             j < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOMap.aiStartIdx +
                     ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.aiSetup.pinNum;
             j++)
        {
            zucInnerDbg("[%f]-", ModbusIOShmStruct->extIOShmStruct.extIOStat.extAI[j]);
        }
        zucInnerDbg("\n");
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOSetup.aoSetup.pinNum = %d\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.aoSetup.pinNum);
        zucInnerDbg("EXTIO:>> ModbusIOShmStruct->extIOShmStruct.extIOModConfig[%d].extIOMap.aoStartIdx = %d\n",
                    i,
                    ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOMap.aoStartIdx);
        for (j = ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOMap.aoStartIdx;
             j < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOMap.aoStartIdx +
                     ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.aoSetup.pinNum;
             j++)
        {
            zucInnerDbg("[%f]-", ModbusIOShmStruct->extIOShmStruct.extIOCtrl.extAO[j]);
        }
        zucInnerDbg("\n");
    }
}
#endif

/**
 * @brief 
 *  * communication init
 * setup connection
 * @return int 
 */
static int extio_commInit()
{
    uint32_t old_response_to_sec;
    uint32_t old_response_to_usec;
    uint32_t new_response_to_sec;
    uint32_t new_response_to_usec;
    int i;

    pthread_mutex_init(&rtu_ctx_lock, NULL);

    for (i = 0; i < MAX_EXTIO_CNT; i++)
    {
        /*init and no fail*/
        local_config_mgr_rtu[i].connection_fail_cnt = 0;
        local_config_mgr_rtu[i].connection_read_in_reg_fail_cnt = 0;
        local_config_mgr_rtu[i].connection_write_reg_fail_cnt = 0;
        local_config_mgr_rtu[i].connection_write_bits_fail_cnt = 0;
        local_config_mgr_rtu[i].connection_read_regs_fail_cnt = 0;
        local_config_mgr_rtu[i].connection_read_bits_fail_cnt = 0;
        local_config_mgr_rtu[i].connection_sts = 0;

        if ((local_config_mgr_rtu[i].extIOCfg.extType == 0) &&
            (local_config_mgr_rtu[i].extIOCfg.commInfo.rtuComm.slaveId > 247 || local_config_mgr_rtu[i].extIOCfg.commInfo.rtuComm.slaveId < 0))
        {
            zucInnerDbg("#########  slaveId=%d  out of range [0, 247]\n", local_config_mgr_rtu[i].extIOCfg.commInfo.rtuComm.slaveId);
            return -1;
        }

        local_config_mgr_rtu[i].supportRobotiq = isRobotiqType(local_config_mgr_rtu[i].extIOCfg.modName);
        local_config_mgr_tcp[i].connection_fail_cnt = 0;
        local_config_mgr_tcp[i].connection_sts = 0;
    }

    /*
	 * modbus-rtu communication init
	 * ttyS3 for now
	 * 
	 */
    if (local_config_mgr_rtu[0].extIOCfg.extType == 0)
    {
        std::string device = ModbusIOShmStruct->extIOShmStruct.cabType >= 2 ? "/dev/ttyS3" : "/dev/ttyS1";
        rtu_ctx = modbus_new_rtu(device.c_str(),
                                 local_config_mgr_rtu[0].extIOCfg.commInfo.rtuComm.baudrate,
                                 local_config_mgr_rtu[0].extIOCfg.commInfo.rtuComm.parity,
                                 local_config_mgr_rtu[0].extIOCfg.commInfo.rtuComm.databits,
                                 local_config_mgr_rtu[0].extIOCfg.commInfo.rtuComm.stopbits);

        /* close debug information of the modbus module*/
        modbus_set_debug(rtu_ctx, FALSE);
        /* set recovery mode*/
        modbus_set_error_recovery(rtu_ctx, (modbus_error_recovery_mode)(MODBUS_ERROR_RECOVERY_LINK | MODBUS_ERROR_RECOVERY_PROTOCOL));

        modbus_get_response_timeout(rtu_ctx, &old_response_to_sec, &old_response_to_usec);

        if (modbus_connect(rtu_ctx) == -1)
        {
            zucInnerDbg("EXTIO:>> Connection failed\n");
            modbus_free(rtu_ctx);
            /*set pointer to NULL incase of wrong free operation*/
            rtu_ctx = NULL;
            return -1;
        }
        /* check timeout configurations
		*  default timeout 500ms
		*/
        modbus_get_response_timeout(rtu_ctx, &new_response_to_sec, &new_response_to_usec);

        if (new_response_to_sec == old_response_to_sec && new_response_to_usec == old_response_to_usec && new_response_to_sec == 0 &&
            new_response_to_usec >= 200000)
        {
            zucInnerDbg("EXTIO:>> extio modbus-rtu communication init successful\n");
        }
    }
    /*
	 * modbus-TCP connection setup
	 * modbus-tcp is based on TCP/IP so every node should have an individle connection
	 * init them one by one and record them
	 */
    int index_tcp_node = 0;
    while (local_config_mgr_tcp[index_tcp_node].extIOCfg.extType == 1)
    {
        local_config_mgr_tcp[index_tcp_node].modbus_ctx = modbus_new_tcp(
            local_config_mgr_tcp[index_tcp_node].extIOCfg.commInfo.tcpComm.ipaddr, local_config_mgr_tcp[index_tcp_node].extIOCfg.commInfo.tcpComm.port, "");

        modbus_set_debug(local_config_mgr_tcp[index_tcp_node].modbus_ctx, FALSE);

        modbus_set_error_recovery(local_config_mgr_tcp[index_tcp_node].modbus_ctx,
                                  (modbus_error_recovery_mode)(MODBUS_ERROR_RECOVERY_LINK | MODBUS_ERROR_RECOVERY_PROTOCOL));

        modbus_get_response_timeout(local_config_mgr_tcp[index_tcp_node].modbus_ctx, &old_response_to_sec, &old_response_to_usec);

        local_config_mgr_tcp[index_tcp_node].supportRobotiq = isRobotiqType(local_config_mgr_tcp[index_tcp_node].extIOCfg.modName);

        if (modbus_connect(local_config_mgr_tcp[index_tcp_node].modbus_ctx) == -1)
        {
            zucInnerDbg("EXTIO:>> Modbus-TCP node: Connection failed\n");
            modbus_close(local_config_mgr_tcp[index_tcp_node].modbus_ctx);
            modbus_free(local_config_mgr_tcp[index_tcp_node].modbus_ctx);
            /*set pointer to NULL incase of wrong free operation*/
            local_config_mgr_tcp[index_tcp_node].modbus_ctx = NULL;
            for (i = 0; i < index_tcp_node; i++)
            {
                modbus_close(local_config_mgr_tcp[i].modbus_ctx);
                modbus_free(local_config_mgr_tcp[i].modbus_ctx);
                /*set pointer to NULL incase of wrong free operation*/
                local_config_mgr_tcp[i].modbus_ctx = NULL;
            }
            if (rtu_ctx != NULL)
            {
                modbus_free(rtu_ctx);
                /*set pointer to NULL incase of wrong free operation*/
                rtu_ctx = NULL;
            }
            /* modbus-TCP connection can not start*/
            // ModbusIOShmStruct->extIOShmStruct.extIOStat.status = 2;
            // ModbusIOShmStruct->extIOShmStruct.extIOStat.errCode = (0x01 << 12) | /*init phase*/
            //                                                       (0x02 << 8) |  /*modbus-tcp*/
            //                                                       (0x02 << 0);   /* connection can not start*/

            return -2;
        }

        modbus_get_response_timeout(local_config_mgr_tcp[index_tcp_node].modbus_ctx, &new_response_to_sec, &new_response_to_usec);

        if (new_response_to_sec == old_response_to_sec && new_response_to_usec == old_response_to_usec && new_response_to_sec == 0 &&
            new_response_to_usec >= 200000)
        {
            zucInnerDbg("EXTIO:>> modbus-TCP communication init successful\n");
        }
        index_tcp_node++;
    }

    for (i = 0; i < MAX_EXTIO_CNT; i++)
    {
        if (local_config_mgr_rtu[i].extIOCfg.extType != 0xFF)
        {
            /*set to normal*/
            local_config_mgr_rtu[i].connection_sts = 1;
        }

        if (local_config_mgr_tcp[i].extIOCfg.extType != 0xFF)
        {
            local_config_mgr_tcp[i].connection_sts = 1;
        }
    }

    return 0;
}
static int extio_commDeInit_flag = 1;
/**
 * @brief 
 * 	free all connections
 */
static void extio_commDeInit()
{
    int i;
    if (extio_commDeInit_flag == 0)
    {
        extio_commDeInit_flag = 1;
        pthread_mutex_lock(&rtu_ctx_lock);
        if (rtu_ctx != NULL)
        {
            modbus_free(rtu_ctx);
            /* set it to the un-init value */
            rtu_ctx = NULL;
        }
        pthread_mutex_unlock(&rtu_ctx_lock);

        for (i = 0; i < 32; i++)
        {
            if (local_config_mgr_tcp[i].extIOCfg.extType == 1)
            {
                if (local_config_mgr_tcp[i].modbus_ctx != NULL)
                {
                    modbus_close(local_config_mgr_tcp[i].modbus_ctx);
                    modbus_free(local_config_mgr_tcp[i].modbus_ctx);
                    /* set it to the un-init value */
                    local_config_mgr_tcp[i].modbus_ctx = NULL;
                }
            }
        }
    }
}

/**
 * @brief 
 *   check consistant of all the configuration
		modbus-rtu all nodes should have the same communication parameter
		if type == rtu or tcp:
			if all cfg consustant : 
				return 0
			else
				return -1
		else:
			return -2
 * @param s 
 * @param c 
 * @return int 
 */
int extio_cntCharInString(char* s, char c)
{
    int cnt = 0;
    if (s == NULL)
    {
        return 0;
    }

    for (size_t i = 0; i < strlen(s); i++)
    {
        if (s[i] == c)
        {
            cnt++;
        }
    }
    return cnt;
}
/**
 * @brief 
 * 		check the parameters of all extio configuration
 * @return int 
 */
static int zuc_modbus_check_cfg_consistant()
{
    int i;
    int index_rtu = 0;
    int index_tcp = 0;

    for (i = 0; i < MAX_EXTIO_CNT; i++)
    {
        local_config_mgr_rtu[i].extIOCfg.extType = 0xFF;
        local_config_mgr_tcp[i].extIOCfg.extType = 0xFF;
    }

    for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModCount; i++)
    {
        /* check communication type and copy it to local structre
		   0: modbus-rtu
		   1: modbus-tcp
		 */
        if (ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.extType == 0)
        {
            //
            memcpy((void*)(&(local_config_mgr_rtu[index_rtu].extIOCfg)),
                   (void*)(&(ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup)),
                   sizeof(ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup));
            local_config_mgr_rtu[index_rtu].shm_index = i;
            index_rtu++;
        }
        else if (ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup.extType == 1)
        {
            memcpy((void*)(&(local_config_mgr_tcp[index_tcp].extIOCfg)),
                   (void*)(&(ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup)),
                   sizeof(ModbusIOShmStruct->extIOShmStruct.extIOModConfig[i].extIOSetup));
            local_config_mgr_tcp[index_tcp].shm_index = i;
            index_tcp++;
        }
        else
        {
            /*  wrong Protocol*/
            ModbusIOShmStruct->extIOShmStruct.extIOStat.status = 2;
            ModbusIOShmStruct->extIOShmStruct.extIOStat.errCode = (0x01 << 12) | /*init phase*/
                                                                  (0x03 << 8) |  /*both or neither*/
                                                                  (0x04 << 0);   /* unknown */

            return -2;
        }
    }

    i = 0;
    /**
	 * @brief 
	 * 
	 * check consistant 
	 * for now just check modbus-rtu communication parameter
	 * modbus-tcp
	 * 
	 */
    //
    while (local_config_mgr_rtu[i].extIOCfg.extType == 0)
    {
        if (local_config_mgr_rtu[i + 1].extIOCfg.extType == 0 &&  //bucong jiance
            local_config_mgr_rtu[i].extIOCfg.commInfo.rtuComm.baudrate == local_config_mgr_rtu[i + 1].extIOCfg.commInfo.rtuComm.baudrate &&
            local_config_mgr_rtu[i].extIOCfg.commInfo.rtuComm.databits == local_config_mgr_rtu[i + 1].extIOCfg.commInfo.rtuComm.databits)
        {
            i++;
        }
        else if (local_config_mgr_rtu[i + 1].extIOCfg.extType == 0xFF)
        {
            return 0;
        }
        else
        {
            /*
			 * wrong cfg
			 */
            ModbusIOShmStruct->extIOShmStruct.extIOStat.status = 2;
            ModbusIOShmStruct->extIOShmStruct.extIOStat.errCode = (0x01 << 12) | /*init phase*/
                                                                  (0x01 << 8) |  /*rtu*/
                                                                  (0x01 << 0);   /* not consistant */

            return -1;
        }
    }

    i = 0;
    int ipStrLen = 0;
    while (local_config_mgr_tcp[i].extIOCfg.extType == 1)
    {
        ipStrLen = strlen(local_config_mgr_tcp[i].extIOCfg.commInfo.tcpComm.ipaddr);
        if ((local_config_mgr_tcp[i].extIOCfg.commInfo.tcpComm.ipaddr[0] >= '0' && local_config_mgr_tcp[i].extIOCfg.commInfo.tcpComm.ipaddr[0] <= '9') &&
            local_config_mgr_tcp[i].extIOCfg.commInfo.tcpComm.ipaddr[ipStrLen - 1] >= '0' &&
            local_config_mgr_tcp[i].extIOCfg.commInfo.tcpComm.ipaddr[ipStrLen - 1] <= '9')
        {
            if (extio_cntCharInString(local_config_mgr_tcp[i].extIOCfg.commInfo.tcpComm.ipaddr, '.') != 3)
            {
                zucInnerDbg("EXTIO:>> Wrong IP ADDRESS: %s\n", local_config_mgr_tcp[i].extIOCfg.commInfo.tcpComm.ipaddr);
                /* * wrong cfg */
                ModbusIOShmStruct->extIOShmStruct.extIOStat.status = 2;
                ModbusIOShmStruct->extIOShmStruct.extIOStat.errCode = (0x01 << 12) | /*init phase*/
                                                                      (0x02 << 8) |  /*tcp*/
                                                                      (0x01 << 0);   /* format error */
                return -1;
            }
        }
        else
        {
            /*
			 * wrong cfg
			 */
            ModbusIOShmStruct->extIOShmStruct.extIOStat.status = 2;
            ModbusIOShmStruct->extIOShmStruct.extIOStat.errCode = (0x01 << 12) | /*init phase*/
                                                                  (0x02 << 8) |  /*tcp*/
                                                                  (0x01 << 0);   /* format error */
            return -1;
        }

        ++i;
    }

    return 0;
}

static int last_mode = 0;
/**
 * @brief 
 * 
 * @return int 
 */
static int check_extio_config()
{
    /* check the extio configurations. 
	 * If it's changed, re-initialize set init reqest. 
	 * if connection failed, 
	 *      return -1. 
	 * If connection status is normal, 
	 *      return 0*/
    if (ModbusIOShmStruct)
    {
        if (last_mode == 0 && ModbusIOShmStruct->extIOShmStruct.mode == 1)
        {  // 0->1
            zucInnerDbg("EXTIO:>>extio entering operation mode!\n");
            zucInnerDbg("EXTIO:>>extio configuration changed, free the formal connection!\n");
            extio_commDeInit();
            modbus_init_cmplt = 0;
            modbus_Init_req = 0;
            usleep(100 * 1000);
            /*
			 * print configuration to screen
			 */
            extio_debug_show_config();

            last_mode = ModbusIOShmStruct->extIOShmStruct.mode;

            if (zuc_modbus_check_cfg_consistant() == 0)
            {
                modbus_Init_req = 1;
                zucInnerDbg("EXTIO:>> zuc_modbus_check_cfg_consistant PASS\n");
            }
            else
            {
                zucInnerDbg("EXTIO:>> zuc_modbus_check_cfg_consistant FAIL\n");
                return -1;
            }
            return 1;
        }
        else if (last_mode == 1 && ModbusIOShmStruct->extIOShmStruct.mode == 0)
        {  //1->0
            zucInnerDbg("EXTIO:>> extio entering maintenance mode!\n");
            /*
			 * if connections have already built
			 * disconnect all connections
			 * ortherwise do nothing
			 */
            if (modbus_init_cmplt == 1)
            {
                extio_commDeInit();
            }
            /*
			 * clear init flag
			 */
            modbus_init_cmplt = 0;
            modbus_Init_req = 0;
            /*
			 * set status maintance
			 * clear error code
			 */
            ModbusIOShmStruct->extIOShmStruct.extIOStat.status = 0;
            ModbusIOShmStruct->extIOShmStruct.extIOStat.errCode = 0x0;

            last_mode = ModbusIOShmStruct->extIOShmStruct.mode;
            return 1;
        }
        else
        {
            if (modbus_Init_req == 1)
                return -1;
#if (EXTIO_MODBUS_DEBUG == 1)
            zucInnerDbg("EXTIO:>> extio Nothing changed!\n");
#endif
            return 0;
        }
    }
    else
    {
        return -1;
    }
}
/**
 * @brief 
 * 
 * @return int 
 */
static int synch_extio_rtu_status()
{
    /*
	 * modbus-rtu status update
	 */
    int i;

    int memory_ao_flag = 0;
    int memory_do_flag = 0;
    int index_sync_rtu = 0;

    static int read_do_flag = 0;
    static int read_ao_flag = 0;

    unsigned char sync_extDO[MAX_EXTIO_DO_NUM] = {0};
    unsigned short sync_extAO[MAX_EXTIO_AO_NUM] = {0};
    unsigned char sync_extDI[MAX_EXTIO_DI_NUM] = {0};
    unsigned short sync_extAI[MAX_EXTIO_AI_NUM] = {0};

    unsigned short sync_extAO_read[MAX_EXTIO_AO_NUM] = {0};
    static unsigned short sync_extAO_temp[MAX_EXTIO_CNT][MAX_EXTIO_AO_NUM] = {0};
    static unsigned short sync_extAO_last[MAX_EXTIO_CNT][MAX_EXTIO_AO_NUM] = {0};

    unsigned char sync_extDO_read[MAX_EXTIO_DO_NUM] = {0};
    static unsigned char sync_extDO_temp[MAX_EXTIO_CNT][MAX_EXTIO_DO_NUM] = {0};
    static unsigned char sync_extDO_last[MAX_EXTIO_CNT][MAX_EXTIO_DO_NUM] = {0};
    int modbus_ret_value;

    while (local_config_mgr_rtu[index_sync_rtu].extIOCfg.extType != 0xFF && index_sync_rtu < 32)
    {
#if (EXTIO_MODBUS_DEBUG == 1)
        zucInnerDbg("EXTIO:>> local_config_mgr_rtu[%d].extIOCfg.extType = 0x%x\n", index_sync_rtu, local_config_mgr_rtu[index_sync_rtu].extIOCfg.extType);
#endif
        if (local_config_mgr_rtu[index_sync_rtu].connection_sts == 1)
        {
            /*
			 * set the to be request Node ID
			 */
            pthread_mutex_lock(&rtu_ctx_lock);
            modbus_set_slave(rtu_ctx, local_config_mgr_rtu[index_sync_rtu].extIOCfg.commInfo.rtuComm.slaveId);
            modbus_set_response_timeout(rtu_ctx, 0, 100000);
            pthread_mutex_unlock(&rtu_ctx_lock);
            // modbus_set_debug(rtu_ctx,1);
            /*
			 * read operations:
			 * input bits
			 * input registers
			 */
            /*
			 * polling delay usleep(10*1000)
			 *
			 * delay should perform between pollings
			 * modbus-rtu need 3.5*(1+8+1) bit time to distinguish request and response
			 * 9600bps need at least 4 ms
			 * make it 10ms to be-sure
			 */
            /*
			 * Digital input reading: DI 
			 */
            if (local_config_mgr_rtu[index_sync_rtu].extIOCfg.diSetup.pinNum > 0)
            {
                for (int cnt = 0; cnt < 5; cnt++)
                {
                    pthread_mutex_lock(&rtu_ctx_lock);
                    modbus_ret_value = modbus_read_input_bits(rtu_ctx,
                                                              local_config_mgr_rtu[index_sync_rtu].extIOCfg.diSetup.startRegAddr,
                                                              local_config_mgr_rtu[index_sync_rtu].extIOCfg.diSetup.pinNum,
                                                              sync_extDI);
                    pthread_mutex_unlock(&rtu_ctx_lock);
                    if (modbus_ret_value >= 0)
                    {
                        break;
                    }
                }
                /*
				 * check access status
				 */
                if (modbus_ret_value < 0)
                {
                    local_config_mgr_rtu[index_sync_rtu].connection_fail_cnt++;
                    goto rtu_error_handle;
                }
                else
                {
                    local_config_mgr_rtu[index_sync_rtu].connection_fail_cnt = 0;
                    usleep(2 * 1000);
                }
            }

            if (local_config_mgr_rtu[index_sync_rtu].extIOCfg.aiSetup.pinNum > 0)
            {
                for (int cnt = 0; cnt < 5; cnt++)
                {
                    pthread_mutex_lock(&rtu_ctx_lock);
                    modbus_ret_value = modbus_read_input_registers(rtu_ctx,
                                                                   local_config_mgr_rtu[index_sync_rtu].extIOCfg.aiSetup.startRegAddr,
                                                                   local_config_mgr_rtu[index_sync_rtu].extIOCfg.aiSetup.pinNum,
                                                                   sync_extAI);
                    pthread_mutex_unlock(&rtu_ctx_lock);
                    if (modbus_ret_value >= 0)
                    {
                        break;
                    }
                }

                /*
				 * check access status
				 */
                if (modbus_ret_value < 0)
                {
                    local_config_mgr_rtu[index_sync_rtu].connection_read_in_reg_fail_cnt++;
                    goto rtu_error_handle;
                }
                else
                {
                    local_config_mgr_rtu[index_sync_rtu].connection_read_in_reg_fail_cnt = 0;
                    usleep(10 * 1000);
                }
            }

            /*
			 * after read operation , update status to share memory
			 */
            for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOSetup.diSetup.pinNum; i++)
            {
                ModbusIOShmStruct->extIOShmStruct.extIOStat
                    .extDI[ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOMap.diStartIdx + i] =
                    (int)sync_extDI[i];
            }
            for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOSetup.aiSetup.pinNum; i++)
            {
                ModbusIOShmStruct->extIOShmStruct.extIOStat
                    .extAI[ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOMap.aiStartIdx + i] =
                    (double)sync_extAI[i];
            }

            /*
			 * before write , get nearest data from extIOCtrl share memory
			 */
            for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOSetup.doSetup.pinNum; i++)
            {
                sync_extDO[i] =
                    (unsigned char)(ModbusIOShmStruct->extIOShmStruct.extIOCtrl.extDO
                                        [ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOMap.doStartIdx +
                                         i]);
                //ModbusIOShmStruct->extIOShmStruct.extIOStat.extDO[ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOMap.doStartIdx + i] = sync_extDO[i];
            }

            for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOSetup.aoSetup.pinNum; i++)
            {
                sync_extAO[i] =
                    (unsigned short)(ModbusIOShmStruct->extIOShmStruct.extIOCtrl.extAO
                                         [ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOMap.aoStartIdx +
                                          i]);
                //ModbusIOShmStruct->extIOShmStruct.extIOStat.extAO[ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOMap.aoStartIdx + i] = sync_extAO[i];
            }
            // check Ao
            for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOSetup.aoSetup.pinNum; i++)
            {
                if (sync_extAO[i] != sync_extAO_last[index_sync_rtu][i])
                {
                    memory_ao_flag = 1;
                    memcpy(sync_extAO_last[index_sync_rtu], sync_extAO, MAX_EXTIO_AO_NUM * sizeof(unsigned short));
                    memcpy(sync_extAO_temp[index_sync_rtu], sync_extAO, MAX_EXTIO_AO_NUM * sizeof(unsigned short));
                    break;
                }
            }
            //  check Do
            for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOSetup.doSetup.pinNum; i++)
            {
                if (sync_extDO[i] != sync_extDO_last[index_sync_rtu][i])
                {
                    memory_do_flag = 1;
                    memcpy(sync_extDO_last[index_sync_rtu], sync_extDO, MAX_EXTIO_DO_NUM * sizeof(unsigned char));
                    memcpy(sync_extDO_temp[index_sync_rtu], sync_extDO, MAX_EXTIO_DO_NUM * sizeof(unsigned char));
                    break;
                }
            }

            if (memory_ao_flag == 1)
            {
                /*
				* write holding registers --AO
				*/
                if (local_config_mgr_rtu[index_sync_rtu].extIOCfg.aoSetup.pinNum > 0)
                {
                    for (int cnt = 0; cnt < 5; cnt++)
                    {
                        pthread_mutex_lock(&rtu_ctx_lock);
                        modbus_ret_value = modbus_write_registers(rtu_ctx,
                                                                  local_config_mgr_rtu[index_sync_rtu].extIOCfg.aoSetup.startRegAddr,
                                                                  local_config_mgr_rtu[index_sync_rtu].extIOCfg.aoSetup.pinNum,
                                                                  sync_extAO_last[index_sync_rtu]);
                        pthread_mutex_unlock(&rtu_ctx_lock);
                        if (modbus_ret_value >= 0)
                        {
                            break;
                        }
                    }

                    /*
					* check access status
					*/
                    if (modbus_ret_value < 0)
                    {
                        local_config_mgr_rtu[index_sync_rtu].connection_write_reg_fail_cnt++;
                        goto rtu_error_handle;
                    }
                    else
                    {
                        local_config_mgr_rtu[index_sync_rtu].connection_write_reg_fail_cnt = 0;
                        usleep(10 * 1000);
                    }
                }

                memory_ao_flag = 0;
            }

            if (memory_do_flag == 1)
            {
                /*
				* write digital outputs
				*/
                if (local_config_mgr_rtu[index_sync_rtu].extIOCfg.doSetup.pinNum > 0)
                {
                    for (int cnt = 0; cnt < 5; cnt++)
                    {
                        pthread_mutex_lock(&rtu_ctx_lock);
                        modbus_ret_value = modbus_write_bits(rtu_ctx,
                                                             local_config_mgr_rtu[index_sync_rtu].extIOCfg.doSetup.startRegAddr,
                                                             local_config_mgr_rtu[index_sync_rtu].extIOCfg.doSetup.pinNum,
                                                             sync_extDO_last[index_sync_rtu]);
                        pthread_mutex_unlock(&rtu_ctx_lock);
                        if (modbus_ret_value >= 0)
                        {
                            break;
                        }
                    }
                    /*
					* check access status
					*/
                    if (modbus_ret_value < 0)
                    {
                        local_config_mgr_rtu[index_sync_rtu].connection_write_bits_fail_cnt++;
                        goto rtu_error_handle;
                    }
                    else
                    {
                        local_config_mgr_rtu[index_sync_rtu].connection_write_bits_fail_cnt = 0;
                        usleep(10 * 1000);
                    }
                }

                memory_do_flag = 0;
            }

            /*
			* read holding reg values from remote device 
			*/
            if (local_config_mgr_rtu[index_sync_rtu].supportRobotiq == 0)
            {
                if (local_config_mgr_rtu[index_sync_rtu].extIOCfg.aoSetup.pinNum > 0)
                {
                    pthread_mutex_lock(&rtu_ctx_lock);
                    for (int cnt = 0; cnt < 5; cnt++)
                    {
                        modbus_ret_value = modbus_read_registers(rtu_ctx,
                                                                 local_config_mgr_rtu[index_sync_rtu].extIOCfg.aoSetup.startRegAddr,
                                                                 local_config_mgr_rtu[index_sync_rtu].extIOCfg.aoSetup.pinNum,
                                                                 sync_extAO_read);
                        if (modbus_ret_value >= 0)
                        {
                            break;
                        }
                    }
                    pthread_mutex_unlock(&rtu_ctx_lock);

                    /*
				* check access status
				*/
                    if (modbus_ret_value < 0)
                    {
                        local_config_mgr_rtu[index_sync_rtu].connection_read_regs_fail_cnt++;
                        goto rtu_error_handle;
                    }
                    else
                    {
                        local_config_mgr_rtu[index_sync_rtu].connection_read_regs_fail_cnt = 0;
                        usleep(10 * 1000);
                    }
                }
            }

            /*
			* read coil reg values  from remote device
			*/
            if (local_config_mgr_rtu[index_sync_rtu].extIOCfg.doSetup.pinNum > 0)
            {
                for (int cnt = 0; cnt < 5; cnt++)
                {
                    pthread_mutex_lock(&rtu_ctx_lock);
                    modbus_ret_value = modbus_read_bits(rtu_ctx,
                                                        local_config_mgr_rtu[index_sync_rtu].extIOCfg.doSetup.startRegAddr,
                                                        local_config_mgr_rtu[index_sync_rtu].extIOCfg.doSetup.pinNum,
                                                        sync_extDO_read);
                    pthread_mutex_unlock(&rtu_ctx_lock);
                    if (modbus_ret_value >= 0)
                    {
                        break;
                    }
                }

                /*
				* check access status
				*/
                if (modbus_ret_value < 0)
                {
                    local_config_mgr_rtu[index_sync_rtu].connection_read_bits_fail_cnt++;
                    goto rtu_error_handle;
                }
                else
                {
                    local_config_mgr_rtu[index_sync_rtu].connection_read_bits_fail_cnt = 0;
                    usleep(10 * 1000);
                }
            }
            //  after read register form remote device check AO
            if (local_config_mgr_rtu[index_sync_rtu].supportRobotiq == 0)
            {
                for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOSetup.aoSetup.pinNum; i++)
                {
                    if (sync_extAO_read[i] != sync_extAO_temp[index_sync_rtu][i])
                    {
                        read_ao_flag = 1;
                        break;
                    }
                }
            }
            //  after read bits form remote device check Do
            for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOSetup.doSetup.pinNum; i++)
            {
                if (sync_extDO_read[i] != sync_extDO_temp[index_sync_rtu][i])
                {
                    read_do_flag = 1;
                    break;
                }
            }

            if (local_config_mgr_rtu[index_sync_rtu].supportRobotiq == 0)
            {
                if (read_ao_flag == 1)
                {
                    //write ao ctrl share memory
                    for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOSetup.aoSetup.pinNum;
                         i++)
                    {
                        ModbusIOShmStruct->extIOShmStruct.extIOCtrl
                            .extAO[ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOMap.aoStartIdx + i] =
                            sync_extAO_read[i];
                        sync_extAO_last[index_sync_rtu][i] = sync_extAO_read[i];
                    }
                    read_ao_flag = 0;
                }
                //write ao stat share memory
                for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOSetup.aoSetup.pinNum; i++)
                {
                    ModbusIOShmStruct->extIOShmStruct.extIOStat
                        .extAO[ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOMap.aoStartIdx + i] =
                        sync_extAO_read[i];
                    sync_extAO_temp[index_sync_rtu][i] = sync_extAO_read[i];
                }
            }
            else
            {
                //write ao stat share memory
                for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOSetup.aoSetup.pinNum; i++)
                {
                    ModbusIOShmStruct->extIOShmStruct.extIOStat
                        .extAO[ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOMap.aoStartIdx + i] =
                        sync_extAO[i];
                }
            }

            if (read_do_flag == 1)
            {
                //write do ctrl share memory
                for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOSetup.doSetup.pinNum; i++)
                {
                    ModbusIOShmStruct->extIOShmStruct.extIOCtrl
                        .extDO[ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOMap.doStartIdx + i] =
                        sync_extDO_read[i];
                    sync_extDO_last[index_sync_rtu][i] = sync_extDO_read[i];
                }

                read_do_flag = 0;
            }
            //write do stat share memory
            for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOSetup.doSetup.pinNum; i++)
            {
                ModbusIOShmStruct->extIOShmStruct.extIOStat
                    .extDO[ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_rtu[index_sync_rtu].shm_index].extIOMap.doStartIdx + i] =
                    sync_extDO_read[i];
                sync_extDO_temp[index_sync_rtu][i] = sync_extDO_read[i];
            }

            /*
			 * update node connection sts
			 */

        rtu_error_handle:
            if ((local_config_mgr_rtu[index_sync_rtu].connection_fail_cnt + local_config_mgr_rtu[index_sync_rtu].connection_read_in_reg_fail_cnt +
                 local_config_mgr_rtu[index_sync_rtu].connection_write_reg_fail_cnt + local_config_mgr_rtu[index_sync_rtu].connection_write_bits_fail_cnt +
                 local_config_mgr_rtu[index_sync_rtu].connection_read_regs_fail_cnt + local_config_mgr_rtu[index_sync_rtu].connection_read_bits_fail_cnt) > 0)
            {
                /*set  the node offline*/
                local_config_mgr_rtu[index_sync_rtu].connection_sts = 2;
                // ModbusIOShmStruct->extIOShmStruct.extIOStat.status = 2;

                if (modbus_Init_req == 0 && modbus_init_cmplt == 0)  // mode  1 ---->  0
                {
                    return 0;
                }

                if (ModbusIOShmStruct->extIOShmStruct.reConnectMaxTimes <= 0)
                {
                    ModbusIOShmStruct->extIOShmStruct.extIOStat.status = 2;
                    ModbusIOShmStruct->extIOShmStruct.extIOStat.errCode = (0x02 << 12) | /*runtime phase*/
                                                                          (0x01 << 8) |  /*rtu*/
                                                                          (0x03 << 0);   /* node offline */
                    modbus_Init_req = 0;
                    modbus_init_cmplt = 0;
                }
                else
                {
                    modbus_Init_req = 1;
                    modbus_init_cmplt = 0;
                    lastExtIOErrCode = (0x02 << 12) | /*runtime phase*/
                                       (0x01 << 8) |  /*rtu*/
                                       (0x03 << 0);   /* node offline */
                    lastExtIOStatus = 2;
                }

                return -1;
            }
        }
        index_sync_rtu++;
    }
    return 0;
}
/**
 * @brief 
 *  * extio modbus-tcp manager
 * modbus-tcp is a protocol base on tcp, 
 * the speed is extreamly higher than modbus-rtu
 * so  give it a thread to keep update the status of all servers
 * 
 * polling delay set to 50 ms 
 * @return int 
 */
static int synch_extio_tcp_status()
{
    int i;
    int index_sync_tcp = 0;
    int modbus_ret_value;
    int memory_ao_flag = 0;
    int memory_do_flag = 0;
    int update_ao_do_wait_flag = 0;

    static int read_do_flag = 0;
    static int read_ao_flag = 0;

    unsigned char sync_extDO[MAX_EXTIO_DO_NUM] = {0};
    unsigned short sync_extAO[MAX_EXTIO_AO_NUM] = {0};
    unsigned char sync_extDI[MAX_EXTIO_DI_NUM] = {0};
    unsigned short sync_extAI[MAX_EXTIO_AI_NUM] = {0};

    unsigned short sync_extAO_read[MAX_EXTIO_AO_NUM] = {0};
    static unsigned short sync_extAO_temp[MAX_EXTIO_CNT][MAX_EXTIO_AO_NUM] = {0};
    static unsigned short sync_extAO_last[MAX_EXTIO_CNT][MAX_EXTIO_AO_NUM] = {0};

    unsigned char sync_extDO_read[MAX_EXTIO_DO_NUM] = {0};
    static unsigned char sync_extDO_temp[MAX_EXTIO_CNT][MAX_EXTIO_DO_NUM] = {0};
    static unsigned char sync_extDO_last[MAX_EXTIO_CNT][MAX_EXTIO_DO_NUM] = {0};
    /*
	 * read write operations
	 * if operation fail, increase the fail counter
	 * if fail counter bigger than 10,
	 *                                       slave/client response  timeout = 500ms, 10times  means 5s 
	 * set node offline
	 * client will not access the node before shut down and power up again
	 */

    while (local_config_mgr_tcp[index_sync_tcp].extIOCfg.extType != 0xFF)
    {
        /*
		 * modbus-tcp  server ID is not necessary
		 * but maybe some node will check ID,
		 * let's assume that ID can be ignore like modbus slave of the PC
		 */
        /*
		 * check connection status then decide access or not
		 */
        if (local_config_mgr_tcp[index_sync_tcp].connection_sts == 1)
        {
            /*
			 * set fixed slave ID
			 */
            //zucInnerDbg("mobus salve id is:%d\n",	local_config_mgr_tcp[index_sync_tcp].extIOCfg.commInfo.tcpComm.slaveId);
            modbus_set_slave(local_config_mgr_tcp[index_sync_tcp].modbus_ctx, local_config_mgr_tcp[index_sync_tcp].extIOCfg.commInfo.tcpComm.slaveId);
            /*
			 * read digital input
			 */
            if (local_config_mgr_tcp[index_sync_tcp].extIOCfg.diSetup.pinNum > 0)
            {
                modbus_ret_value = modbus_read_input_bits(local_config_mgr_tcp[index_sync_tcp].modbus_ctx,
                                                          local_config_mgr_tcp[index_sync_tcp].extIOCfg.diSetup.startRegAddr,
                                                          local_config_mgr_tcp[index_sync_tcp].extIOCfg.diSetup.pinNum,
                                                          sync_extDI);
                /*
				 * check access status
				 */
                if (modbus_ret_value < 0)
                {
                    local_config_mgr_tcp[index_sync_tcp].connection_fail_cnt++;
                    goto error_handle;
                }
                else
                {
                    local_config_mgr_tcp[index_sync_tcp].connection_fail_cnt = 0;
                }
            }
            /*
			 * read input registers
			 */
            if (local_config_mgr_tcp[index_sync_tcp].extIOCfg.aiSetup.pinNum > 0)
            {
                modbus_ret_value = modbus_read_input_registers(local_config_mgr_tcp[index_sync_tcp].modbus_ctx,
                                                               local_config_mgr_tcp[index_sync_tcp].extIOCfg.aiSetup.startRegAddr,
                                                               local_config_mgr_tcp[index_sync_tcp].extIOCfg.aiSetup.pinNum,
                                                               sync_extAI);
                /*
				 * check access status
				 */
                if (modbus_ret_value < 0)
                {
                    local_config_mgr_tcp[index_sync_tcp].connection_fail_cnt++;
                    goto error_handle;
                }
                else
                {
                    local_config_mgr_tcp[index_sync_tcp].connection_fail_cnt = 0;
                }
            }
            /*
			 * after read operation , update status to share memory
			 */
            for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOSetup.diSetup.pinNum; i++)
            {
                ModbusIOShmStruct->extIOShmStruct.extIOStat
                    .extDI[ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOMap.diStartIdx + i] =
                    (int)sync_extDI[i];
            }

            for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOSetup.aiSetup.pinNum; i++)
            {
                ModbusIOShmStruct->extIOShmStruct.extIOStat
                    .extAI[ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOMap.aiStartIdx + i] =
                    (double)sync_extAI[i];
            }
            /*
			 * before write , get newest data from share memory
			 */
            for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOSetup.doSetup.pinNum; i++)
            {
                sync_extDO[i] =
                    (unsigned char)(ModbusIOShmStruct->extIOShmStruct.extIOCtrl.extDO
                                        [ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOMap.doStartIdx +
                                         i]);
                //ModbusIOShmStruct->extIOShmStruct.extIOStat.extDO[ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOMap.doStartIdx + i] = sync_extDO[i];
            }

            for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOSetup.aoSetup.pinNum; i++)
            {
                sync_extAO[i] =
                    (unsigned short)(ModbusIOShmStruct->extIOShmStruct.extIOCtrl.extAO
                                         [ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOMap.aoStartIdx +
                                          i]);
                //ModbusIOShmStruct->extIOShmStruct.extIOStat.extAO[ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOMap.aoStartIdx + i] = sync_extAO_temp[index_sync_tcp][i];
            }
            //  check Ao value
            for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOSetup.aoSetup.pinNum; i++)
            {
                if (sync_extAO[i] != sync_extAO_last[index_sync_tcp][i])
                {
                    memory_ao_flag = 1;
                    memcpy(sync_extAO_last[index_sync_tcp], sync_extAO, MAX_EXTIO_AO_NUM * sizeof(unsigned short));
                    memcpy(sync_extAO_temp[index_sync_tcp], sync_extAO, MAX_EXTIO_AO_NUM * sizeof(unsigned short));
                    break;
                }
            }
            //  check Do value
            for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOSetup.doSetup.pinNum; i++)
            {
                if (sync_extDO[i] != sync_extDO_last[index_sync_tcp][i])
                {
                    memory_do_flag = 1;
                    memcpy(sync_extDO_last[index_sync_tcp], sync_extDO, MAX_EXTIO_DO_NUM * sizeof(unsigned char));
                    memcpy(sync_extDO_temp[index_sync_tcp], sync_extDO, MAX_EXTIO_DO_NUM * sizeof(unsigned char));
                    break;
                }
            }

            if (memory_ao_flag == 1)
            {
                /*
				* write holding registers --AO
				*/
                if (local_config_mgr_tcp[index_sync_tcp].extIOCfg.aoSetup.pinNum > 0)
                {
                    modbus_ret_value = modbus_write_registers(local_config_mgr_tcp[index_sync_tcp].modbus_ctx,
                                                              local_config_mgr_tcp[index_sync_tcp].extIOCfg.aoSetup.startRegAddr,
                                                              local_config_mgr_tcp[index_sync_tcp].extIOCfg.aoSetup.pinNum,
                                                              sync_extAO_last[index_sync_tcp]);
                    /*
					* check access status
					*/
                    if (modbus_ret_value < 0)
                    {
                        local_config_mgr_tcp[index_sync_tcp].connection_fail_cnt++;
                        goto error_handle;
                    }
                    else
                    {
                        local_config_mgr_tcp[index_sync_tcp].connection_fail_cnt = 0;
                    }
                }

                memory_ao_flag = 0;
                update_ao_do_wait_flag = 1;
            }
            //TO DO optimize
            if (memory_do_flag == 1)
            {
                /*
				* write digital outputs
				*/
                if (local_config_mgr_tcp[index_sync_tcp].extIOCfg.doSetup.pinNum > 0)
                {
                    modbus_ret_value = modbus_write_bits(local_config_mgr_tcp[index_sync_tcp].modbus_ctx,
                                                         local_config_mgr_tcp[index_sync_tcp].extIOCfg.doSetup.startRegAddr,
                                                         local_config_mgr_tcp[index_sync_tcp].extIOCfg.doSetup.pinNum,
                                                         sync_extDO_last[index_sync_tcp]);
                    /*
					* check access status
					*/
                    if (modbus_ret_value < 0)
                    {
                        local_config_mgr_tcp[index_sync_tcp].connection_fail_cnt++;
                        goto error_handle;
                    }
                    else
                    {
                        local_config_mgr_tcp[index_sync_tcp].connection_fail_cnt = 0;
                    }
                }

                memory_do_flag = 0;
                update_ao_do_wait_flag = 1;
            }

            /*
			* read holding reg values from remote device 
			*/
            if (local_config_mgr_tcp[index_sync_tcp].supportRobotiq == 0)
            {
                if (update_ao_do_wait_flag == 1)
                {
                    //如果向从站写了DO、AO，且需要回读写入后的从站DO、AO状态，则等待30ms后再读，避免从站更新慢，读不到正确结果。
                    usleep(30 * 1000);
                    update_ao_do_wait_flag = 0;
                }

                if (local_config_mgr_tcp[index_sync_tcp].extIOCfg.aoSetup.pinNum > 0)
                {
                    modbus_ret_value = modbus_read_registers(local_config_mgr_tcp[index_sync_tcp].modbus_ctx,
                                                             local_config_mgr_tcp[index_sync_tcp].extIOCfg.aoSetup.startRegAddr,
                                                             local_config_mgr_tcp[index_sync_tcp].extIOCfg.aoSetup.pinNum,
                                                             sync_extAO_read);

                    /*
					* check access status
					*/
                    if (modbus_ret_value < 0)
                    {
                        local_config_mgr_tcp[index_sync_tcp].connection_fail_cnt++;
                        goto error_handle;
                    }
                    else
                    {
                        local_config_mgr_tcp[index_sync_tcp].connection_fail_cnt = 0;
                    }
                }

                /*
                * read coil reg values  from remote device
                */
                if (local_config_mgr_tcp[index_sync_tcp].extIOCfg.doSetup.pinNum > 0)
                {
                    modbus_ret_value = modbus_read_bits(local_config_mgr_tcp[index_sync_tcp].modbus_ctx,
                                                        local_config_mgr_tcp[index_sync_tcp].extIOCfg.doSetup.startRegAddr,
                                                        local_config_mgr_tcp[index_sync_tcp].extIOCfg.doSetup.pinNum,
                                                        sync_extDO_read);

                    /*
				* check access status
				*/
                    if (modbus_ret_value < 0)
                    {
                        local_config_mgr_tcp[index_sync_tcp].connection_fail_cnt++;
                        goto error_handle;
                    }
                    else
                    {
                        local_config_mgr_tcp[index_sync_tcp].connection_fail_cnt = 0;
                    }
                }
            }

            if (local_config_mgr_tcp[index_sync_tcp].supportRobotiq == 0)
            {
                for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOSetup.aoSetup.pinNum; i++)
                {
                    if (sync_extAO_read[i] != sync_extAO_temp[index_sync_tcp][i])
                    {
                        read_ao_flag = 1;
                        break;
                    }
                }

                //  after read bits form remote device check Do
                for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOSetup.doSetup.pinNum; i++)
                {
                    if (sync_extDO_read[i] != sync_extDO_temp[index_sync_tcp][i])
                    {
                        read_do_flag = 1;
                        break;
                    }
                }
            }

            if (local_config_mgr_tcp[index_sync_tcp].supportRobotiq == 0)
            {
                if (read_do_flag == 1)
                {
                    //write do share memory
                    for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOSetup.doSetup.pinNum;
                         i++)
                    {
                        ModbusIOShmStruct->extIOShmStruct.extIOCtrl
                            .extDO[ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOMap.doStartIdx + i] =
                            sync_extDO_read[i];
                        sync_extDO_last[index_sync_tcp][i] = sync_extDO_read[i];
                    }

                    read_do_flag = 0;
                }

                //write do share memory
                for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOSetup.doSetup.pinNum; i++)
                {
                    ModbusIOShmStruct->extIOShmStruct.extIOStat
                        .extDO[ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOMap.doStartIdx + i] =
                        sync_extDO_read[i];
                    sync_extDO_temp[index_sync_tcp][i] = sync_extDO_read[i];
                }

                if (read_ao_flag == 1)
                {
                    //write ao share memory
                    for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOSetup.aoSetup.pinNum;
                         i++)
                    {
                        ModbusIOShmStruct->extIOShmStruct.extIOCtrl
                            .extAO[ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOMap.aoStartIdx + i] =
                            sync_extAO_read[i];
                        sync_extAO_last[index_sync_tcp][i] = sync_extAO_read[i];
                    }
                    read_ao_flag = 0;
                }

                //write ao share memory
                for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOSetup.aoSetup.pinNum; i++)
                {
                    ModbusIOShmStruct->extIOShmStruct.extIOStat
                        .extAO[ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOMap.aoStartIdx + i] =
                        sync_extAO_read[i];
                    sync_extAO_temp[index_sync_tcp][i] = sync_extAO_read[i];
                }
            }
            else
            {
                //write do share memory
                for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOSetup.doSetup.pinNum; i++)
                {
                    ModbusIOShmStruct->extIOShmStruct.extIOStat
                        .extDO[ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOMap.doStartIdx + i] =
                        sync_extDO[i];
                }

                //write ao share memory
                for (i = 0; i < ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOSetup.aoSetup.pinNum; i++)
                {
                    ModbusIOShmStruct->extIOShmStruct.extIOStat
                        .extAO[ModbusIOShmStruct->extIOShmStruct.extIOModConfig[local_config_mgr_tcp[index_sync_tcp].shm_index].extIOMap.aoStartIdx + i] =
                        sync_extAO[i];
                }
            }

            /*
			 * update node connection sts
			 */
        error_handle:
            if (local_config_mgr_tcp[index_sync_tcp].connection_fail_cnt >= 1)
            {
                /*set  the node offline*/
                local_config_mgr_tcp[index_sync_tcp].connection_sts = 2;
                /*
				 * connection fail, delete the connection
				 */
                modbus_close(local_config_mgr_tcp[index_sync_tcp].modbus_ctx);
                modbus_free(local_config_mgr_tcp[index_sync_tcp].modbus_ctx);
                local_config_mgr_tcp[index_sync_tcp].modbus_ctx = NULL;

                if (ModbusIOShmStruct->extIOShmStruct.reConnectMaxTimes <= 0)
                {
                    modbus_Init_req = 0;
                    modbus_init_cmplt = 0;
                    ModbusIOShmStruct->extIOShmStruct.extIOStat.status = 2;
                    ModbusIOShmStruct->extIOShmStruct.extIOStat.errCode = (0x02 << 12) | /*runtime phase*/
                                                                          (0x02 << 8) |  /*tcp*/
                                                                          (0x03 << 0);   /* node offline */
                }
                else
                {
                    modbus_Init_req = 1;
                    modbus_init_cmplt = 0;
                    lastExtIOErrCode = (0x02 << 12) | /*runtime phase*/
                                       (0x02 << 8) |  /*tcp*/
                                       (0x03 << 0);   /* node offline */
                    lastExtIOStatus = 2;
                }

                return -1;
            }
        }
        index_sync_tcp++;
    }
    return 0;
}

/**
 * @brief 
 * 
 * Function name: extio_mgr
 * Description: main thread function of the extio management, 
 *    which will be called every two servo periods
 * 
 * @param arg 
 */

void extio_rtu_mgr()
{
    while (!quit_flag)
    {
        if (modbus_init_cmplt == 1)
        {
            if (ModbusIOShmStruct->extIOShmStruct.extIOStat.status == 1)
            {
                if (synch_extio_rtu_status() != 0)
                {  // retrun  -1
                    extioRTU_offlineCnt++;
                    if (ModbusIOShmStruct->extIOShmStruct.reConnectMaxTimes == 0)
                    {
                        extioRTU_offlineCnt = 0;
                    }
                }
                else  //  return 0
                {
                    extioRTU_offlineCnt = 0;
                }
            }
            usleep(10 * 1000);
        }
        else
        {
#if (EXTIO_MODBUS_DEBUG == 1)
            zucInnerDbg("EXTIO:>> modbus-RTU wait for init OR re-init\n");
#endif
            usleep(100 * 1000);
        }
    }
    return;
}

void extio_tcp_mgr()
{
    while (!quit_flag)
    {
        usleep(10 * 1000);
        if (check_extio_config() == 0)
        {
            if (modbus_init_cmplt == 1)
            {
                if (ModbusIOShmStruct->extIOShmStruct.extIOStat.status == 1)
                {
                    synch_extio_tcp_status();  //
                }
#if (EXTIO_MODBUS_DEBUG == 1)
                zucInnerDbg("EXTIO:>> synch_extio_tcp_status \n");
                extio_debug_show_data();
#endif
            }
        }
        else
        {
            zucInnerDbg("EXTIO:>> Perform Init Operation_1 modbus_Init_req %d,  modbus_init_cmplt =%d  status:%d\n",
                        modbus_Init_req,
                        modbus_init_cmplt,
                        ModbusIOShmStruct->extIOShmStruct.extIOStat.status);
            if (modbus_Init_req == 1 && modbus_init_cmplt != 1)
            {
                int initRet = extio_commInit();
                zucInnerDbg("EXTIO:>> Perform Init Operation   extioRTU_offlineCnt:%d / reConnectMaxTimes:%d ,reConnectCnt=%d, return %d\n",
                            extioRTU_offlineCnt,
                            ModbusIOShmStruct->extIOShmStruct.reConnectMaxTimes,
                            reConnectCnt,
                            initRet);
                reConnectCnt++;
                if (initRet == 0 && extioRTU_offlineCnt <= ModbusIOShmStruct->extIOShmStruct.reConnectMaxTimes)
                {
                    modbus_init_cmplt = 1;
                    modbus_Init_req = 0;
                    reConnectCnt = 0;
                    /* 
					 * default operation 
					 * module get into running status after init
					 * status can be changed from upper layer 
					 *  extio status RUNNING
					 */
                    ModbusIOShmStruct->extIOShmStruct.extIOStat.status = 1;
                    extio_commDeInit_flag = 0;
                }
                else
                {
                    if ((reConnectCnt) >= ModbusIOShmStruct->extIOShmStruct.reConnectMaxTimes ||
                        (extioRTU_offlineCnt > ModbusIOShmStruct->extIOShmStruct.reConnectMaxTimes))
                    {
                        reConnectCnt = 0;
                        modbus_Init_req = 0;
                        modbus_init_cmplt = 0;
                        extioRTU_offlineCnt = 0;

                        if (lastExtIOErrCode != 0)
                        {
                            ModbusIOShmStruct->extIOShmStruct.extIOStat.errCode = lastExtIOErrCode;
                            ModbusIOShmStruct->extIOShmStruct.extIOStat.status = lastExtIOStatus;
                            lastExtIOStatus = 0;
                            lastExtIOErrCode = 0;
                        }
                        else
                        {
                            switch (initRet)
                            {
                            case -1:
                                /* modbus-RTU connection can not start */
                                ModbusIOShmStruct->extIOShmStruct.extIOStat.status = 2;
                                ModbusIOShmStruct->extIOShmStruct.extIOStat.errCode = (0x01 << 12) | /*init phase*/
                                                                                      (0x01 << 8) |  /*modbus-rtu*/
                                                                                      (0x02 << 0);   /* connection can not start*/
                                break;
                            case -2:
                                /* modbus-TCP connection can not start*/
                                ModbusIOShmStruct->extIOShmStruct.extIOStat.status = 2;
                                ModbusIOShmStruct->extIOShmStruct.extIOStat.errCode = (0x01 << 12) | /*init phase*/
                                                                                      (0x02 << 8) |  /*modbus-tcp*/
                                                                                      (0x02 << 0);   /* connection can not start*/
                                break;
                            default:
                                break;
                            }
                        }
                    }
                    else
                    {
                        if (ModbusIOShmStruct->extIOShmStruct.reConnectInterval > 50)
                        {
                            usleep((ModbusIOShmStruct->extIOShmStruct.reConnectInterval - 50) * 1000);
                        }
                        else
                        {
                            usleep(50 * 1000);
                        }
                    }
                }
            }
        }
    }
    /*
	 * quit signal recved
	 */
    extio_commDeInit();
    return;
}
